package me.ycy.android.couchbase.server

import android.app.Activity
import android.os.Bundle
import android.content.Intent
import android.util.Log
import android.view.{ View, ContextMenu, MenuItem }
import android.widget._
import android.content.ServiceConnection

import com.couchbase.android.CouchbaseMobile
import com.couchbase.android.ICouchbaseDelegate

import org.codehaus.jackson.map.ObjectMapper

import java.io.IOException
import java.util.Date
import java.util.{ List => jList, Map => jMap }

import replication._
import replication.ReplicatorDb.{ withReplicators, modifyReplicators }

class MainActivity extends Activity {
  val Tag = "CouchbaseServer"

  val ActivityResultEdit = 1

  lazy val self = this

  var conn: ServiceConnection = null

  protected def handleEvent: Unit = {
    val cl = new this.ClickListener
    (findViewById(R.id.repAdd).asInstanceOf[Button]).setOnClickListener(cl)
  }

  private[this] class ClickListener extends View.OnClickListener {
    def onClick(v: View): Unit = {
      v.getId match {
        case R.id.repAdd =>
          ReplicationEdit.add(self, ActivityResultEdit)
        case _ =>
      }
    }
  }

  lazy val repList = findViewById(R.id.repList).asInstanceOf[ListView]
  lazy val repAdapter = new ReplicationAdapter(this)

  def updateReplicator = this.runOnUiThread (new Runnable {
    def run = repAdapter.notifyDataSetChanged
  })

  private[this] def serviceChange(s: Boolean): Unit = {
    val i: Intent = new Intent(this, classOf[CouchbaseService])
    if (s) startService(i) else stopService(i)
  }

  var statusUpdaterThread: Thread = null
  class statusUpdater extends Thread {
    import scala.collection.JavaConversions._

    var running = true
    var delay = 5000
    val om = new ObjectMapper

    def extract(r: Replicator, t: Map[String, Object]): Boolean = {
      // Log.d(Tag, "status: " + t)
      var changed = false
      try {
        if (t("type") != "replication") throw new Exception
        if (!t("replication_id").toString.contains(r.replicationId)) {
          throw new Exception
        }

        val uo = new Date(t("updated_on").toString.toLong * 1000)
        if (r.updatedOn != uo) {
          r.updatedOn = uo
          changed = true
        }

        val so = new Date(t("started_on").toString.toLong * 1000)
        if (r.startedOn != so) {
          r.startedOn = so
          changed = true
        }

        val st = "seq: " + t("source_seq").toString + " / " +
          "checkpointed seq: " + t("checkpointed_source_seq").toString
        if (r.status != st) {
          r.status = st
          changed = true
        }
      }
      catch { case _ => }

      changed
    }

    override def run = {
      Log.i(Tag, "status updater stated.")
      while(running) {
        try {
          if (ReplicatorDb.db != null) {
            val c = ReplicatorDb.db.getConnection
            val res = c.get("/_active_tasks")
            if (res.isSuccessful) {
              val a = om.readValue(res.getContent,
                                   classOf[jList[jMap[String, Object]]])
              val b = a.toList.map(_.toMap)
              var changed = false
              modifyReplicators { rs => {
                rs.foreach { x => {
                  b.foreach { t => changed ||= extract(x._2, t) }
                }}
                rs
              }}
              if (changed) {
                updateReplicator
              }
            }
          }
        }
        catch {
          case _: InterruptedException => running = false
          case e => {
            Log.e(Tag, "status updater error: " + e.getMessage)
            e.printStackTrace
          }
        }

        try { Thread.sleep(delay) }
        catch { case _ => running = false }
      }
      Log.i(Tag, "status updater stopped.")
    }
  }

  override def onCreate(savedInstanceState: Bundle) : Unit = {
    Log.d(Tag, "MainActivity onCreate")

    super.onCreate(savedInstanceState)
    setContentView(R.layout.main)
    handleEvent

    // check data
    repList.setAdapter(repAdapter)

    registerForContextMenu(repList)

    repList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
      def onItemClick(parent: AdapterView[_],
                      view: View,
                      pos: Int, id: Long) {
        val obj = withReplicators(_.apply(id))

        new Thread {
          override def run = {
            var res: Option[Throwable] = None
            try {
              ReplicatorDb.save(obj) // trigger replication
            }
            catch {
              case e => res = Some(e)
            }
            self.runOnUiThread(new Runnable {
              def run = res match {
                case Some(e) =>
                  Toast.makeText(getApplicationContext(),
                                 "replication " + obj.id + " error " + e.getMessage,
                                 Toast.LENGTH_LONG).show()
                case _ =>
                  Toast.makeText(self.getApplicationContext(),
                                 "replication " + obj.id + " started",
                                 Toast.LENGTH_SHORT).show()
              }
            })
          }
        }.start
      }
    })

    // pass references to service
    ReplicatorDb.setUiUpdater(() => updateReplicator)

    serviceChange(true)
  }

  override def onPause(): Unit = {
    Log.d(Tag, "MainActivity onPause")
    ReplicatorDb.resetUiUpdater()
    if (statusUpdaterThread != null) {
      statusUpdaterThread.interrupt
      statusUpdaterThread = null
    }
    super.onPause()
  }

  override def onResume(): Unit = {
    super.onResume()

    Log.d(Tag, "MainActivity onResume")

    statusUpdaterThread = new statusUpdater
    statusUpdaterThread.start

    ReplicatorDb.setUiUpdater(() => updateReplicator)
    // update repAdapter
    repAdapter.notifyDataSetChanged
  }

  override def onDestroy(): Unit = {
    Log.d(Tag, "MainActivity onDestroy")

    ReplicatorDb.resetUiUpdater()

    unregisterForContextMenu(repList)
    super.onDestroy()
  }


  override def onCreateContextMenu(menu: ContextMenu, v: View,
                                   menuInfo: ContextMenu.ContextMenuInfo) = {
    super.onCreateContextMenu(menu, v, menuInfo);
    val inflater = getMenuInflater();
    inflater.inflate(R.menu.replication_menu, menu)
  }

  override def onContextItemSelected(item: MenuItem): Boolean = {
    val info = item.getMenuInfo().
      asInstanceOf[AdapterView.AdapterContextMenuInfo]

    item.getItemId() match {
      case R.id.repMenuEdit => {
        Log.d(Tag, "menu info id " + info.id)
        val obj = withReplicators(_.apply(info.id))
        ReplicationEdit.edit(this, ActivityResultEdit, obj.id)
        return true
      }
      case R.id.repMenuDelete => {
        Log.d(Tag, "menu info id " + info.id)
        val obj = withReplicators(_.apply(info.id))
        try {
          ReplicatorDb.delete(obj)
        }
        catch { case e => {
          Log.e(Tag, "delete error " + e.getMessage)
          e.printStackTrace
        }}
        return true
      }
      case _ =>
        return super.onContextItemSelected(item)
    }
  }

}
